home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / Tools / Text-Viewer / MSWordView / notes / ole / olelibexplanation next >
Encoding:
Text File  |  1999-03-29  |  11.3 KB  |  392 lines

  1. X-RDate: Fri, 09 Oct 1998 09:15:15 +0100 (IST)
  2. Received: from mailgate.ul.ie ([136.201.1.23]) by exch-staff1.ul.ie with SMTP
  3.  (Microsoft Exchange Internet Mail Service Version 5.5.1960.3) id 4QKT1D00;
  4.  Fri, 9 Oct 1998 08:58:53 +0100
  5. Received: from gatekeeper.research.natpower.co.uk by mailgate.ul.ie with SMTP
  6.  (PP) id <25470-0@mailgate.ul.ie>; Fri, 9 Oct 1998 09:13:56 +0000
  7. Received: by gatekeeper.research.natpower.co.uk id AA17695 (InterLock SMTP
  8.  Gateway 3.0 for caolan.mcnamara@ul.ie); Fri, 9 Oct 1998 09:13:01 +0100
  9. Received: by gatekeeper.research.natpower.co.uk (Protected-side Proxy Mail
  10.  Agent-2); Fri, 9 Oct 1998 09:13:01 +0100
  11. Received: by gatekeeper.research.natpower.co.uk (Protected-side Proxy Mail
  12.  Agent-1); Fri, 9 Oct 1998 09:13:01 +0100
  13. Message-ID: <199810090813.AA17695@gatekeeper.research.natpower.co.uk>
  14. Date: Fri, 9 Oct 1998 10:12:58 +0100
  15. MIME-Version: 1.0
  16. Content-Type: text/plain; charset="US-ASCII"
  17. XFMstatus: 0000
  18. From: Andrew Scriven <andy.scriven@research.natpower.co.uk>
  19. To: Filters Proyect <filters@centauri.lci.ulsa.mx>
  20. Subject: RE: Which streams are toplevel in which tree?
  21. Cc: Caolan McNamara <Caolan.McNamara@ul.ie>
  22.  
  23. Hi, 
  24.  
  25. Caolan copied me your email. Perhaps I can explain.
  26.  
  27. The code I wrote does parse the OLE tree fully in its original form. In
  28. fact I 
  29. attach a small C program, called OLEread.c which prints out the full
  30. tree 
  31. structure. 
  32.  
  33. Caolan tells me he only needs the "top level" entries from the OLE file,
  34. so in 
  35. the code I sent him, only those entries are extracted. Question is how
  36. to find 
  37. this "top level" linked list? Have a look at the recursive function
  38. "unravel" 
  39. in the C code.
  40.  
  41. If you start with the list of pps entries, one of them, usually the
  42. first, has 
  43. a "type" of 5 which means Root. All pps entries have pointers to
  44. previous, 
  45. next and directory pps entires. The Root pps entry will have a directory
  46. entry 
  47. which is effectively the "top" of the tree.
  48.  
  49. If you start with the pps pointed to by this Root->directory, and start
  50. to 
  51. follow it, it will unravel into a list of linked pps entries. However,
  52. the 
  53. list will consist of previous and next references and also some
  54. directory 
  55. entries. 
  56.  
  57. If all you want is the "top level" list, you simply DO NOT follow the 
  58. directory entries.
  59.  
  60. The code I attach DOES follow the directory entries just to print out
  61. the 
  62. tree, but it keeps track of what "level" of nesting you are at.
  63.  
  64. So a typical OLE doc may look like this
  65.  
  66.                   Root
  67.                    |
  68.                    3
  69.                   / \
  70.                  5   6- dir- 8
  71.                 / \   \     / \
  72.                9   8   10  4   2
  73.            
  74.  
  75. the top level list would be
  76.        9-5-8-3-6-10
  77.   and you ignore 4-8-2 as this is "nested" under 6.
  78.  
  79. Happy?
  80.  
  81. Andrew
  82. -----------------------------------------------------------------------
  83. Andrew Scriven
  84. Research and Engineering
  85. Electron Building, Windmill Hill, Whitehill Way, Swindon, SN5 6PB, UK
  86. Phone (44) 1793 896206, Fax (44) 1793 896251
  87. -----------------------------------------------------------------------
  88.  
  89. #include <stdio.h>
  90. #include <stdarg.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93. #include <malloc.h>
  94. #include <ctype.h>
  95. #include <sys/types.h>
  96. #include <assert.h>
  97.  
  98. #define MIN(a,b) ((a)<(b) ? (a) : (b))
  99. #define MAXBLOCKS 64
  100.  
  101. struct pps_block
  102.   {
  103.   char name[64];
  104.   int nsize;
  105.   char type;
  106.   struct pps_block *previous;
  107.   struct pps_block *next;
  108.   struct pps_block *directory;
  109.   long int start;
  110.   long int size;
  111.   int level;
  112.   int index;
  113.   };
  114.  
  115. typedef struct pps_block pps_entry;
  116.  
  117. char *pps_type[]={"","DIR ","FILE","","","ROOT"};
  118.  
  119. /* Routine prototypes */
  120. unsigned short int ShortInt(unsigned char* array);
  121. unsigned long int LongInt(unsigned char* array);
  122.  
  123. unsigned short int ShortInt(unsigned char* array)
  124. {
  125. union two_byte {
  126.  unsigned short int num;
  127.  char  ch[2];
  128.  } Short;
  129.  
  130. #ifndef INTEL
  131.   Short.ch[1] = *array++;
  132.   Short.ch[0] = *array;
  133. #else
  134.   Short.ch[0] = *array++;
  135.   Short.ch[1] = *array;
  136. #endif
  137. return Short.num;
  138.  
  139. }
  140.  
  141. unsigned long int LongInt(unsigned char* array)
  142. {
  143. union four_byte {
  144.  unsigned long int num;
  145.  char  ch[4];
  146.  } Long;
  147.  
  148. #ifndef INTEL
  149.   Long.ch[3] = *array++;
  150.   Long.ch[2] = *array++;
  151.   Long.ch[1] = *array++;
  152.   Long.ch[0] = *array;
  153. #else
  154.   Long.ch[0] = *array++;
  155.   Long.ch[1] = *array++;
  156.   Long.ch[2] = *array++;
  157.   Long.ch[3] = *array;
  158. #endif
  159. return Long.num;
  160. }
  161.  
  162. /* recurse to follow forward/backward list of root pps's */
  163. void unravel(pps_entry *pps_node, int level)
  164. {
  165.   if(pps_node->nsize ==0) return;
  166.   if(pps_node->previous != NULL) unravel(pps_node->previous,level);
  167.   pps_node->level = level;
  168.   printf("PPS %s: %*x: ->
  169. %s\n",pps_type[pps_node->type],level*3,pps_node->
  170. index,pps_node->name);
  171.   if(pps_node->directory != NULL) unravel(pps_node->directory,level+1);
  172.   if(pps_node->next != NULL) unravel(pps_node->next,level);
  173. }
  174.  
  175. int main(int argc, char **argv)
  176. {
  177.   FILE *input=NULL;
  178.   FILE *OLEfile=NULL;
  179.   FILE *sbfile=NULL;
  180.   FILE *infile=NULL;
  181.   char Target[64];
  182.   int debug=0, BlockSize=0,Offset=0;
  183.   int c,i,j,k,len,bytes;
  184.   char *s,*p,*t;
  185.   char *Block,*BDepot,*SDepot,*Depot,*Root;
  186.   char Name[64];
  187.   unsigned long int FilePos=0x00000000;
  188.   long int num_bbd_blocks;
  189.   long int root_list[MAXBLOCKS], sbd_list[MAXBLOCKS];
  190.   long int pps_size,pps_start=-1;
  191.   long int linkto;
  192.   int root_entry;
  193.   pps_entry **pps_list;
  194.  
  195.   if(argc < 2) {
  196.     fprintf(stderr,"No input file name\n");
  197.     exit (12);
  198.   }
  199.   fprintf(stderr,"File given was %s\n",argv[1]);
  200.   input = fopen(argv[1], "rb");
  201.   if(input==NULL) {
  202.     fprintf(stderr,"Error opening file %s\n",argv[1]);
  203.     exit (12);
  204.   }
  205.   if(argc < 3) {
  206.     fprintf(stderr,"Listing contents\n");
  207.     strncpy(Target,"UnLiKeLy",8);
  208.   } else {
  209.     strncpy(Target,argv[2],64);
  210.     fprintf(stderr,"Extracting %s...\n",Target);
  211.   }
  212.  
  213.   /* peek into file to guess file type */
  214.   c=getc(input);
  215.   ungetc(c,input);
  216.  
  217.   if(isprint(c)) {
  218.      fprintf(stderr,"File looks like a plain text file.\n");
  219.      return 8;
  220.   /* check for MS OLE wrapper */
  221.   } else if(c==0xd0) {
  222.      Block = malloc(512);
  223.      /* read header block */
  224.      if(fread(Block,512,1,input)!=1) {
  225.        fprintf(stderr,"1 ===========> Input file has faulty OLE
  226. format\n");
  227.         exit (5);
  228.      }
  229.      num_bbd_blocks=LongInt(Block+0x2c);
  230.      BDepot = malloc(512*num_bbd_blocks);
  231.      s = BDepot;
  232.      root_list[0]=LongInt(Block+0x30);
  233.      sbd_list[0]=LongInt(Block+0x3c);
  234.      if(debug) fprintf(stderr,"num_bbd_blocks %ld, root start %ld, sbd
  235. start 
  236. %ld\n",num_bbd_blocks,root_list[0],sbd_list[0]);
  237.  
  238.      /* read big block Depot */
  239.      for(i=0;i<(int)num_bbd_blocks;i++) {
  240.        FilePos = 512*(LongInt(Block+0x4c+(i*4))+1);
  241.        fseek(input,FilePos,SEEK_SET);
  242.        if(fread(s,512,1,input)!=1) {
  243.          fprintf(stderr,"2 ===========> Input file has faulty bbd\n");
  244.          exit (5);
  245.        }
  246.        s += 0x200;
  247.      }
  248.  
  249.      /* Extract the sbd block list */
  250.      for(len=1;len<MAXBLOCKS;len++){
  251.        sbd_list[len] = LongInt(BDepot+(sbd_list[len-1]*4));
  252.        if(sbd_list[len]==-2) break;
  253.      }
  254.      if(len>=MAXBLOCKS) fprintf(stderr,"Help too many sbd blocks\n");
  255.      SDepot = malloc(512*len);
  256.      s = SDepot;
  257.      /* Read in Small Block Depot */
  258.      for(i=0;i<len;i++) {
  259.        FilePos = 512 *(sbd_list[i]+1);
  260.        fseek(input,FilePos,SEEK_SET);
  261.        if(fread(s,512,1,input)!=1) {
  262.          fprintf(stderr,"3 ===========> Input file has faulty OLE
  263. format\n");
  264.          return 5;
  265.        }
  266.        s += 0x200;
  267.      }
  268.      /* Extract the root block list */
  269.      for(len=1;len<MAXBLOCKS;len++){
  270.        root_list[len] = LongInt(BDepot+(root_list[len-1]*4));
  271.        fprintf(stderr,"root block %d\n",len);
  272.        if(root_list[len]==-2) break;
  273.      }
  274.      if(len>=MAXBLOCKS) fprintf(stderr,"Help too many root blocks\n");
  275.      Root = malloc(512*len);
  276.      s = Root;
  277.      /* Read in Root stream data */
  278.      for(i=0;i<len;i++) {
  279.        FilePos = 512 *(root_list[i]+1);
  280.        fseek(input,FilePos,SEEK_SET);
  281.        if(fread(s,512,1,input)!=1) {
  282.          fprintf(stderr,"4 ===========> Input file has faulty OLE
  283. format\n");
  284.          return 5;
  285.        }
  286.        s += 0x200;
  287.      }
  288.  
  289.      /* assign space for pps list */
  290.      pps_list = malloc(len*4*sizeof(pps_entry *));
  291.      for(j=0;j<len*4;j++) pps_list[j] = malloc(sizeof(pps_entry));
  292.      /* Store pss entry details and look out for Root Entry */
  293.      for(j=0;j<len*4;j++) {
  294.        pps_list[j]->level = -1;
  295.        pps_list[j]->index = j;
  296.        s = Root+(j*0x80);
  297.        /* some pps names have first byte as an integer !!
  298.           so we make it visible so you can extract a named pps */
  299.        if(!isprint(*s)) *s = *s + 48;
  300.        pps_list[j]->nsize=ShortInt(s+0x40);
  301.        if(pps_list[j]->nsize == 0) continue;
  302.        for(p=pps_list[j]->name,t=s;t<s+pps_list[j]->nsize;t++) *p++ =
  303. *t++;
  304.        s+=0x42;
  305.        pps_list[j]->type = *s;
  306.        if(pps_list[j]->type == 5) {
  307.          root_entry = j; /* this is root */
  308.        }
  309.        s+=0x02;
  310.        linkto = LongInt(s);
  311.        if(linkto != -1) pps_list[j]->previous = pps_list[linkto];
  312.        else pps_list[j]->previous = NULL;
  313.        s+=0x04;
  314.        linkto = LongInt(s);
  315.        if(linkto != -1) pps_list[j]->next = pps_list[linkto];
  316.        else pps_list[j]->next = NULL;
  317.        s+=0x04;
  318.        linkto = LongInt(s);
  319.        if(linkto != -1) pps_list[j]->directory = pps_list[linkto];
  320.        else pps_list[j]->directory = NULL;
  321.        s+=0x28;
  322.        pps_list[j]->start = LongInt(s);
  323.        s+=0x04;
  324.        pps_list[j]->size = LongInt(s);
  325.      }
  326.  
  327.      /* go through the pps entries, tagging them with level number
  328.         use recursive routine to follow list starting at root entry */
  329.      unravel(pps_list[root_entry],0);
  330.  
  331.      /* go through the level 0 list looking for named entries */
  332.      for(j=0;j<len*4;j++) {
  333.        if(pps_list[j]->nsize == 0) continue; /* skip empty pps */
  334.        /* we mostly only want the top level (level 1) stuff, so
  335.           here we skip anything more deeply nested. */
  336.        if(pps_list[j]->level > 1) continue;
  337.        pps_start = pps_list[j]->start;
  338.        pps_size  = pps_list[j]->size;
  339.        OLEfile = NULL;
  340.        if(pps_list[j]->type==5) {  /* Root entry */
  341.          OLEfile = tmpfile();
  342.          sbfile = OLEfile;
  343.          if(debug) fprintf(stderr,"Reading sbFile %ld\n",pps_start);
  344.        }
  345.        else if(!strcmp(pps_list[j]->name,Target)) {
  346.          OLEfile=fopen("OLE.tmp","w+b");  /* try and open */
  347.          printf("Reading Target %s\n",Target);
  348.        }
  349.        if(pps_size<=0) OLEfile = NULL;
  350.        if(OLEfile == NULL) continue;
  351.        if(pps_size>=4096 | OLEfile==sbfile) {
  352.          Offset = 1;
  353.          BlockSize = 512;
  354.          infile = input;
  355.          Depot = BDepot;
  356.        } else {
  357.          Offset = 0;
  358.          BlockSize = 64;
  359.          infile = sbfile;
  360.          Depot = SDepot;
  361.        }
  362.        while(pps_start != -2) {
  363.          if(debug) fprintf(stderr,"Reading block %ld\n",pps_start);
  364.          FilePos = (pps_start+Offset)* BlockSize;
  365.          bytes = MIN(BlockSize,pps_size);
  366.          fseek(infile,FilePos,SEEK_SET);
  367.          if(fread(Block,bytes,1,infile)!=1) {
  368.            fprintf(stderr,"5 ===========> Input file has faulty OLE
  369. format\n");
  370.            exit (5);
  371.          }
  372.          fwrite(Block,bytes,1,OLEfile);
  373.          pps_start = LongInt(Depot+(pps_start*4));
  374.          pps_size -= BlockSize;
  375.          if(pps_size <= 0) pps_start=-2;
  376.        }
  377.        rewind(OLEfile);
  378.      }
  379.     for(j=0;j<len*4;j++) free(pps_list[j]);
  380.     free(pps_list);
  381.     free(Root);
  382.     free(BDepot);
  383.     free(Block);
  384.     fclose(input);
  385.     return 0;
  386.   } else {
  387.     /* not a OLE file! */
  388.     fprintf(stderr,"7 ===========> Input file is not an OLE file\n");
  389.     exit (8);
  390.   }
  391. }
  392.